/*
 * @Author: wuqingchun
 * @Date: 2024-05-07 19:31:17
 * @Description: 环形缓冲区实现
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-05-08 13:13:26
 */
#ifndef __RING_BUFFER_H__
#define __RING_BUFFER_H__

#include <cstddef>
#include <atomic>

/**
 * @brief 单生产者单消费者无锁环形缓冲区
 * 
 * @tparam T     缓冲区存储数据类型
 * @tparam buffer_capacity - 缓冲区容量 
 */

template <typename T, size_t buffer_capacity>
class RingBuffer
{
    static constexpr size_t ARRAY_INDEX_MASK = buffer_capacity - 1;

    static_assert((buffer_capacity & ARRAY_INDEX_MASK) == 0, "ring buffer capacity is not a power of 2");
private:
    /** 
     * m_apData 为存储数据的指针数组，使用者需要保存加入缓冲区中的数据在从缓冲区删除之前一直有效
     * m_ulHead 和 m_ulTail分别为加入缓冲区序号和读取序号，一直递增，在保证 m_ulHead 与 m_ulTail的距离不大于
     * 缓冲区的容量前提下，m_ulTail 追赶 m_ulHead
     * 
     * 按照上述规则，只要 buffer_capacity 不超过指定类型的最大值，通过 m_ulHead - m_ulTail >= buffer_capacity
     * 可以判断缓冲区是否满
     * 1. m_ulHead 和 m_ulTail 均没有溢出 
     * 2. m_ulHead 溢出后翻转，m_ulTail 没有溢出
     * 3. m_ulHead 和 m_ulTail 均溢出，类似第一种情况
     */
    const T* m_apData[buffer_capacity];
    size_t m_ulHead;
    size_t m_ulTail;

    std::atomic<size_t> m_atmHead {0};
    std::atomic<size_t> m_atmTail {0};
public:
    RingBuffer(/* args */):
        m_ulHead(0),
        m_ulTail(0)
    {

    }

    ~RingBuffer()
    {

    }

    bool Push(const T* pData)
    {
        if (m_ulHead - m_ulTail >= buffer_capacity)
        {
            // 队列满
            return false;
        }

        m_apData[m_ulHead & ARRAY_INDEX_MASK] = pData;
        std::atomic_thread_fence(std::memory_order_release);
        //printf("Push pData: %p, Head: %lu, Tail: %lu\n", pData, m_ulHead, m_ulTail);
        m_ulHead++;
        
        return true;
    }

    const T* Pop()
    {
        if (m_ulTail == m_ulHead)
        {
            // 队列为空
            return nullptr;
        }

        const T* pTail = m_apData[m_ulTail & ARRAY_INDEX_MASK];
        std::atomic_thread_fence(std::memory_order_release);
        //printf("Pop pData: %p, Head: %lu, Tail: %lu\n", pTail, m_ulHead, m_ulTail);
        m_ulTail++;

        return pTail;
    }

    const T* Peek()
    {
        if (m_ulTail == m_ulHead)
        {
            // 队列为空
            return nullptr;
        }

        return m_apData[m_ulTail & ARRAY_INDEX_MASK];
    }


    bool AtmPush(const T* pData)
    {
        size_t ulHead = m_atmHead.load();
        if (ulHead - m_atmTail.load() == buffer_capacity)
        {
            return false;
        }

        m_apData[ulHead++ & ARRAY_INDEX_MASK] = pData;
        m_atmHead.store(ulHead);

        return true;
    }

    const T* AtmPop()
    {
        size_t ulTail = m_atmTail.load();
        if (ulTail == m_atmHead.load())
        {
            return nullptr;
        }

        const T* pTail = m_apData[ulTail++ & ARRAY_INDEX_MASK];
        m_atmTail.store(ulTail);

        return pTail;
    }

    bool IsEmpty()
    {
        if (m_ulHead == m_ulTail)
        {
            return true;
        }

        return false;
    }

    bool IsFull()
    {
        return (m_ulHead - m_ulTail >= buffer_capacity);
    }

    size_t GetSize() const noexcept
    {       
        return m_ulHead - m_ulTail;
    }

    void Debug()
    {
        printf("Head: %lu, Tail: %lu\n", m_ulHead, m_ulTail);

        for (size_t ulIndex = 0; ulIndex < buffer_capacity; ulIndex++)
        {
            printf("[%d]: %p\n", ulIndex, m_apData[ulIndex]);
        }
    }
};

#endif //__RING_BUFFER_H__